	package utility.cipher;

	import java.io.ByteArrayOutputStream;
	import java.security.InvalidKeyException;
	import java.security.NoSuchAlgorithmException;

	import javax.crypto.BadPaddingException;
	import javax.crypto.Cipher;
	import javax.crypto.IllegalBlockSizeException;
	import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.SecretKeySpec;

	class Encryptor {
		enum Key {
			XUNIQ     (0, "chuoihex"),
			SERVER_URL(1, "chuoihexa");

			private int index;
			private byte[] key;

			private Key(int index, String key)
			{
				this.index = index;
				this.key = toByteArray(key);
			}

			byte[] getKey()
			{
				return key;
			}

			int getIndex()
			{
				return index;
			}

			public static Key valueOf(int index)
			{
				Key keys[] = Key.values();
				for(Key key: keys)
				{
					if(key.getIndex() == index) return key;
				}

				new IllegalArgumentException("Unknown key index: " + index);
				return null;
			}
		}

		private static final String[] ALGORITHMS = {
			"AES"
		};

		static String encrypt(String value, Key key) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
			// アルゴリズムとキーの選択
			int algorithmIndex = 0;
			String algorithm = ALGORITHMS[algorithmIndex];

			// 暗号化
			Cipher cipher = Cipher.getInstance(algorithm);
			cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key.getKey(), algorithm));
			String encrypted = toHexString(cipher.doFinal(value.getBytes()));

			// アルゴリズムとキーのインデックスを付与する
			return Integer.toString(algorithmIndex) + Integer.toString(key.getIndex()) + encrypted;
		}

		static String decrypt(String value) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
			// アルゴリズムとキーの選択
			int algorithmIndex, keyIndex;
			try{
				algorithmIndex = Integer.parseInt(value.substring(0, 1));
			}catch(Exception e){
				throw new NoSuchAlgorithmException(e.getMessage());
			}
			try{
				keyIndex = Integer.parseInt(value.substring(1, 2));
			}catch(Exception e){
				throw new InvalidKeyException(e.getMessage());
			}

			validate(algorithmIndex, keyIndex);

			String algorithm = ALGORITHMS[algorithmIndex];
			Key key = Key.valueOf(keyIndex);

			// アルゴリズムとキーのインデックス(先頭2バイト)を除去
			value = value.substring(2);

			// 復号化
			Cipher cipher = Cipher.getInstance(algorithm);
			cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key.getKey(), algorithm));
			return new String(cipher.doFinal(toByteArray(value)));
		}

		private static String toHexString(byte[] bytes)
		{
			StringBuffer hexString = new StringBuffer();
			for(int i = 0; i < bytes.length; i ++){
				String hex = Integer.toHexString(bytes[i] & 0xff);
				if(hex.length() == 1) hexString.append("0");
				hexString.append(hex);
			}
			return hexString.toString();
		}

		private static byte[] toByteArray(String value)
		{
			ByteArrayOutputStream bytes = new ByteArrayOutputStream();
			for(int i = 0; i < value.length(); i += 2){
				int b = Integer.parseInt(value.substring(i, i + 2), 16);
				bytes.write(b);
			}
			return bytes.toByteArray();
		}

		private static void validate(int algorithmIndex, int keyIndex) throws NoSuchAlgorithmException, InvalidKeyException
		{
			if(algorithmIndex < 0 || algorithmIndex >= ALGORITHMS.length) throw new NoSuchAlgorithmException("Invalid algorithm index.");
			try{
				Key key = Key.valueOf(keyIndex);
				if(key == null) throw new InvalidKeyException("Invalid key index.");
			}catch(Exception e){
				throw new InvalidKeyException("Invalid key index.");
			}
		}

		public static void main(String[] args) throws Exception {
			String serverUrl = "url";
			String ss = "";

			Key key = Key.valueOf(1);

			System.out.println(Encryptor.decrypt(ss));
			System.out.println(Encryptor.encrypt(serverUrl, key));

			System.out.println("-----");
			serverUrl = "ur";
			System.out.println(Encryptor.encrypt(serverUrl, key));
/*
			ss = Encryptor.encrypt(serverUrl, key);
			System.out.println(Encryptor.decrypt(ss));

			serverUrl = "http://d-tran.ds01.info/mysql.php";
			System.out.println(Encryptor.encrypt(serverUrl, key));
*/
			System.out.println(Encryptor.decrypt("encoded"));
		}

	}
